/**
 * @author Jason Pratt
 */

package edu.cmu.cs.stage3.alice.authoringtool.util;

import edu.cmu.cs.stage3.alice.authoringtool.AuthoringTool;
import edu.cmu.cs.stage3.alice.authoringtool.AuthoringToolResources;
import edu.cmu.cs.stage3.alice.authoringtool.datatransfer.CallToUserDefinedQuestionPrototypeReferenceTransferable;
import edu.cmu.cs.stage3.alice.authoringtool.datatransfer.CallToUserDefinedResponsePrototypeReferenceTransferable;
import edu.cmu.cs.stage3.alice.authoringtool.datatransfer.CommonMathQuestionsTransferable;
import edu.cmu.cs.stage3.alice.authoringtool.datatransfer.ElementReferenceTransferable;
import edu.cmu.cs.stage3.alice.authoringtool.datatransfer.PropertyReferenceTransferable;
import edu.cmu.cs.stage3.alice.authoringtool.datatransfer.QuestionPrototypeReferenceTransferable;
import edu.cmu.cs.stage3.alice.authoringtool.datatransfer.ResponsePrototypeReferenceTransferable;
import edu.cmu.cs.stage3.alice.authoringtool.util.event.DnDManagerListener;
import edu.cmu.cs.stage3.awt.AWTUtilities;
import edu.cmu.cs.stage3.awt.SemitransparentWindow;

public class DnDGroupingPanel extends GroupingPanel {

 protected java.awt.datatransfer.Transferable transferable;
 protected DnDGrip grip = new DnDGrip();
 protected java.awt.dnd.DragSource dragSource = new java.awt.dnd.DragSource();
 protected java.awt.Point hotSpot = new java.awt.Point( 0, 0 );
 protected java.awt.dnd.DragSourceListener dndManagerListener = DnDManager.getInternalListener();
 protected edu.cmu.cs.stage3.alice.authoringtool.util.DragWindow dragWindow; //window that could be dragged
 protected SemitransparentWindow dragWindow2;
 protected java.awt.Point dragOffset;
 protected int arcWidth = 12;
 protected int arcHeight = 10;
 protected GroupingPanelDragGestureListener dragGestureListener = new GroupingPanelDragGestureListener();
 protected java.util.LinkedList dragGestureRecognizers = new java.util.LinkedList(); //MEMFIX
 protected boolean dragEnabled = true;
 protected boolean drawFaded = false;
 protected java.awt.Composite defaultComposite = java.awt.AlphaComposite.SrcOver;
 protected java.awt.AlphaComposite alphaComposite = java.awt.AlphaComposite.getInstance( java.awt.AlphaComposite.SRC_OVER, .5f );
 protected boolean isSystemDefined = false;

 private static int staticCont=0;
 public final int cont;
 public static int getStaticCont () { return staticCont; }

 //
 // Panel with a group of components - including other 'GroupingPanel'
 // 
 public DnDGroupingPanel () {
  // System.out.println("DnDGroupingPanel.java: "+staticCont);
  this.cont = staticCont++;
//if (this.cont==63) {
//   System.out.println("DnDGroupingPanel.java: dragEnabled="+dragEnabled+": #="+this.cont);
//   }
//if ((!edu.cmu.cs.stage3.alice.authoringtool.JAlice.isApplet() && this.cont==61)
//    || (edu.cmu.cs.stage3.alice.authoringtool.JAlice.isApplet() && this.cont==63))
//  try{String str="";System.out.println(str.charAt(3));}catch(Exception e) {e.printStackTrace();}

  setLayout( new java.awt.BorderLayout( 2, 2 ) );
  //outerBorder = new edu.cmu.cs.stage3.alice.authoringtool.border.PartialLineBorder( java.awt.Color.lightGray, 1, true, true, true, true );
  //border = javax.swing.BorderFactory.createCompoundBorder( outerBorder, innerBorder );
  //setBorder( border );
  setBorder( javax.swing.BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) );
  setOpaque( false );

  add( grip, java.awt.BorderLayout.WEST ); // DnDGrip grip: add a "grip" area at the left of the component
  addDragSourceComponent( grip );
  addDragSourceComponent( this );
  }

 public java.awt.datatransfer.Transferable getTransferable () {
  return transferable;
  }

 public void setTransferable (java.awt.datatransfer.Transferable transferable) {
  // System.out.println("\n\nDnDGroupingPanel.java: setTransferable("+edu.cmu.cs.stage3.util.StrUtilities.getComponentName(transferable)+")");
  this.transferable = transferable;
  if (transferable != null) {
   if (AuthoringToolResources.safeIsDataFlavorSupported(transferable, PropertyReferenceTransferable.propertyReferenceFlavor )) {
    isSystemDefined = true;
   } else if(AuthoringToolResources.safeIsDataFlavorSupported(transferable, ResponsePrototypeReferenceTransferable.responsePrototypeReferenceFlavor ) && ! AuthoringToolResources.safeIsDataFlavorSupported(transferable, CallToUserDefinedResponsePrototypeReferenceTransferable.callToUserDefinedResponsePrototypeReferenceFlavor )) {
    isSystemDefined = true;
   } else if (AuthoringToolResources.safeIsDataFlavorSupported(transferable, QuestionPrototypeReferenceTransferable.questionPrototypeReferenceFlavor ) && ! AuthoringToolResources.safeIsDataFlavorSupported(transferable, CallToUserDefinedQuestionPrototypeReferenceTransferable.callToUserDefinedQuestionPrototypeReferenceFlavor )) {
    isSystemDefined = true;
   } else if (AuthoringToolResources.safeIsDataFlavorSupported(transferable, CommonMathQuestionsTransferable.commonMathQuestionsFlavor )) {
    isSystemDefined = true;
   } else {
    isSystemDefined = false;
    }
   }
  }

 public boolean isDragEnabled () {
  return this.dragEnabled;
  }

 public void setDragEnabled (boolean b) {
  //System.out.println("DnDGroupingPanel.java: setDragEnabled("+b+") ---------------------------------------------------------- ");
  this.dragEnabled = b;
  }

 public static String trunca (java.awt.Component component) {
  String str = ""+component;
  int tam = str.length();
  str = str.substring(0,tam>85?85:tam);
  return str;
  }

 public void addDragSourceComponent (java.awt.Component component) {
  //System.out.println("DnDGroupingPanel.java: addDragSourceComponent: "+this.cont+": "+trunca(component));
  try {
  for (java.util.Iterator iter = dragGestureRecognizers.iterator(); iter.hasNext();) {
   java.awt.dnd.DragGestureRecognizer dgr = (java.awt.dnd.DragGestureRecognizer)iter.next();
   if (dgr.getComponent() == component) {
    //if (this.cont==63)
    //System.out.println("DnDGroupingPanel.java: addDragSourceComponent: "+this.cont+" return");
    return; // HACK
    }
   }
  if (dragSource != null) { // java.util.LinkedList dragGestureRecognizers; java.awt.dnd.DragSource dragSource
   dragGestureRecognizers.add(dragSource.createDefaultDragGestureRecognizer( component, java.awt.dnd.DnDConstants.ACTION_COPY_OR_MOVE | java.awt.dnd.DnDConstants.ACTION_LINK, dragGestureListener ));
   // System.out.println("DnDGroupingPanel.java: addDragSourceComponent: "+this.cont+": "+str);
   // if (this.cont==63) System.out.println("DnDGroupingPanel.java: addDragSourceComponent: "+this.cont+" dragGestureRecognizers.add(...)");
  } else {
   System.err.println("Error: DnDGroupingPanel.java: addDragSourceComponent: "+this.cont+": "+trunca(component));
   AuthoringTool.getInstance().showErrorDialog( "dragSource is null", null );
   }
  } catch (Exception e) {e.printStackTrace();}
  }

 public void removeDragSourceComponent (java.awt.Component component) {
  for (java.util.ListIterator iter = dragGestureRecognizers.listIterator(); iter.hasNext();) {
   java.awt.dnd.DragGestureRecognizer dgr = (java.awt.dnd.DragGestureRecognizer)iter.next();
   if (dgr.getComponent() == component) {
    dgr.removeDragGestureListener( dragGestureListener );
    dgr.setComponent( null );
    iter.remove();
    // System.out.println("DnDGroupingPanel.java: removeDragSourceComponent: "+this.cont+": "+trunca(component));
    break;
    }
   }
  }

 public java.awt.dnd.DragSource getDragSource () {
  return dragSource;
  }

 public void reset () {
  add( grip, java.awt.BorderLayout.WEST );
  addDragSourceComponent( grip );
  addDragSourceComponent( this );
  }

 //Rem @Override
 public void release () {
  super.release();
  for (java.util.Iterator iter = dragGestureRecognizers.listIterator(); iter.hasNext();) { //MEMFIX
   java.awt.dnd.DragGestureRecognizer dgr = (java.awt.dnd.DragGestureRecognizer)iter.next();
   if (dragGestureListener != null) {
    dgr.removeDragGestureListener( dragGestureListener );
    iter.remove();
    //System.out.println("DnDGroupingPanel.java: release: "+this.cont+": "+trunca(dgr.getComponent()));
    }
   //System.out.println("DnDGroupingPanel.java: release: "+this.cont+": "+trunca(dgr.getComponent()));
   dgr.setComponent( null );
   }
  }

 public java.awt.Image getImage () {
  java.awt.Rectangle bounds = getBounds();
  java.awt.image.BufferedImage image = new java.awt.image.BufferedImage( bounds.width, bounds.height, java.awt.image.BufferedImage.TYPE_INT_ARGB );
  java.awt.Graphics2D g = image.createGraphics();
  paintAll( g );
  return image;
  }

 //Rem @Override
 public void paintComponent (java.awt.Graphics g) {
  super.paintComponent( g );
  Object oldAntialiasing = null;
  if (g instanceof java.awt.Graphics2D) {
   oldAntialiasing = ((java.awt.Graphics2D)g).getRenderingHint( java.awt.RenderingHints.KEY_ANTIALIASING );
   ((java.awt.Graphics2D)g).addRenderingHints( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_ANTIALIASING, java.awt.RenderingHints.VALUE_ANTIALIAS_ON ) );
   }
  java.awt.Rectangle bounds = getBounds();

  g.setColor( getBackground() );
  g.fillRoundRect( 0, 0, bounds.width, bounds.height, arcWidth, arcHeight );
  g.setColor( java.awt.Color.lightGray );
  g.drawRoundRect( 0, 0, bounds.width - 1, bounds.height - 1, arcWidth, arcHeight );

  if (g instanceof java.awt.Graphics2D) {
   ((java.awt.Graphics2D)g).addRenderingHints( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_ANTIALIASING, oldAntialiasing ) );
   }
  }

 //Rem @Override
 public void paintForeground (java.awt.Graphics g) {
  super.paintForeground( g );

  if (isSystemDefined && false) {
   java.awt.Rectangle bounds = getBounds();

   Object oldAntialiasing = null;
   if (g instanceof java.awt.Graphics2D) {
    oldAntialiasing = ((java.awt.Graphics2D)g).getRenderingHint( java.awt.RenderingHints.KEY_ANTIALIASING );
    ((java.awt.Graphics2D)g).addRenderingHints( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_ANTIALIASING, java.awt.RenderingHints.VALUE_ANTIALIAS_ON ) );
    }

   int w = bounds.width;
   int h = bounds.height;
   int s = 7;
   g.setColor( new java.awt.Color( 220, 220, 220 ) );
   g.fillPolygon( new int[] { 0, 0, s }, new int[] { s, 0, 0 }, 3 ); // upper left
   g.fillPolygon( new int[] { w - s, w, w }, new int[] { 0, 0, s }, 3 ); // upper right
   g.fillPolygon( new int[] { 0, 0, s }, new int[] { h - s, h, h }, 3 ); // lower left
   g.fillPolygon( new int[] { w, w, w - s }, new int[] { h - s, h, h }, 3 ); // lower right
   w--;
   h--;
   s--;
   g.setColor( new java.awt.Color( 160, 160, 160 ) );
   g.drawPolygon( new int[] { 0, 0, s }, new int[] { s, 0, 0 }, 3 ); // upper left
   g.drawPolygon( new int[] { w - s, w, w }, new int[] { 0, 0, s }, 3 ); // upper right
   g.drawPolygon( new int[] { 0, 0, s }, new int[] { h - s, h, h }, 3 ); // lower left
   g.drawPolygon( new int[] { w, w, w - s }, new int[] { h - s, h, h }, 3 ); // lower right

   if (g instanceof java.awt.Graphics2D) {
    ((java.awt.Graphics2D)g).addRenderingHints( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_ANTIALIASING, oldAntialiasing ) );
    }
   }
  }

 // public class GroupingPanelDragGestureListener implements java.awt.dnd.DragGestureListener
 public class GroupingPanelDragGestureListener implements java.awt.dnd.DragGestureListener {
  protected class DragListener extends java.awt.event.MouseAdapter implements java.awt.event.MouseMotionListener {
   //Rem @Override
   public void mouseReleased (java.awt.event.MouseEvent ev) {
    drawFaded = false;
    DnDGroupingPanel.this.repaint();
    dragWindow.setVisible( false );
    AWTUtilities.removeMouseListener( this );
    AWTUtilities.removeMouseMotionListener( this );
    DnDManager.removeListener( dragSourceListener );
System.out.println("DnDGroupingPanel.java: class GroupingPanelDragGestureListener: mouseReleased(MouseEvent): faz 'DnDManager.removeListener(dragSourceListener): "+ev.paramString());
    }

   public void mouseDragged (java.awt.event.MouseEvent ev) {
System.out.println("DnDGroupingPanel.java: class GroupingPanelDragGestureListener: mouseDragged(MouseEvent): "+ev.paramString());
    java.awt.Point p = ev.getPoint();
    p.x -= dragOffset.x;
    p.y -= dragOffset.y;
    if ((dragWindow2 != null)) {
     dragWindow2.show();
     dragWindow2.setLocationOnScreen( p.x, p.y );
     AWTUtilities.pumpMessageQueue();
    } else if (dragWindow != null) {
     dragWindow.setVisible(true);
     dragWindow.setLocation( p );
     }
    }

   public void mouseMoved (java.awt.event.MouseEvent ev) {}
   } // protected class DragListener extends java.awt.event.MouseAdapter implements java.awt.event.MouseMotionListener

  // protected class DragSourceListener
  protected class DragSourceListener implements DnDManagerListener {

   public void dragEnter (java.awt.dnd.DragSourceDragEvent dsde) {
try{System.out.println("DnDGroupingPanel.java: class GroupingPanelDragGestureListener: dragEnter(DragSourceDragEvent): component="+edu.cmu.cs.stage3.util.StrUtilities.getComponentName(dsde.getDragSourceContext().getComponent()));
} catch(Exception e){e.printStackTrace();}
    GroupingPanelDragGestureListener.this.updateImages( true );
    }

   public void dragExit (java.awt.dnd.DragSourceEvent ev) {
    GroupingPanelDragGestureListener.this.updateImages( false );
    //try{String str=""; System.out.println(str.charAt(3));}catch(Exception e) {e.printStackTrace();}
    }

   //
   public void dragDropEnd (java.awt.dnd.DragSourceDropEvent ev) { } //System.out.println("DnDGroupingPanel.java: "+ev);

   public void dragOver (java.awt.dnd.DragSourceDragEvent ev) {}
   public void dropActionChanged (java.awt.dnd.DragSourceDragEvent ev) {}
   public void dragGestureRecognized (java.awt.dnd.DragGestureEvent ev) {}
   public void dragStarted () {}
   } // class DragSourceListener implements DnDManagerListener

  protected DragSourceListener dragSourceListener = new DragSourceListener();

  public void dragGestureRecognized (java.awt.dnd.DragGestureEvent dge) {
String str="";
try {
 if (DnDGroupingPanel.this.transferable != null) {
  Object obj = DnDGroupingPanel.this.transferable;
  if (obj instanceof ElementReferenceTransferable) str = " - transferable="+((ElementReferenceTransferable)transferable).getElement();
  else str = " - transferable="+transferable;

    DnDManager.fireDragGestureRecognized( dge );
    try {
     if (dragEnabled) {
      dge.startDrag( java.awt.dnd.DragSource.DefaultCopyDrop, DnDGroupingPanel.this.transferable, DnDManager.getInternalListener() );

      DnDManager.fireDragStarted(DnDGroupingPanel.this.transferable, DnDGroupingPanel.this); // java.awt.datatransfer.Transferable transferable
      drawFaded = true;
      DnDGroupingPanel.this.repaint();
      }
    } catch (Throwable t) {
      System.err.println("Error: DnDGroupingPanel.java: class GroupingPanelDragGestureListener: dragGestureRecognized(java.awt.dnd.DragGestureEvent): dragEnabled: "+str);
      AuthoringTool.getInstance().showErrorDialog( "Error initiating drag of tile.", t );
      }
    }
   } catch (Exception e) { e.printStackTrace(); }

   }

  private boolean updateImages (boolean valid) {
   java.awt.Image tileImage = DnDGroupingPanel.this.getImage();
   boolean scaledAndCropped = false;

   if (AuthoringToolResources.safeIsDataFlavorSupported(DnDGroupingPanel.this.transferable, ElementReferenceTransferable.responseReferenceFlavor )
       || AuthoringToolResources.safeIsDataFlavorSupported(DnDGroupingPanel.this.transferable, AuthoringToolResources.getReferenceFlavorForClass(edu.cmu.cs.stage3.alice.core.question.userdefined.Component.class) )) {
    int width = tileImage.getWidth( GUIEffects.sizeObserver );
    int height = tileImage.getHeight( GUIEffects.sizeObserver );

    if ((width > 64) || (height > 64)) {
     double scaleFactor = 1.0;
     java.awt.Rectangle cropRect = new java.awt.Rectangle( 0, 0, 64, 64 );
     if ((width > 128) && (height > 128)) { // if both dimensions are > 128, scale by 0.5
      scaleFactor = 0.5;
     } else if (height < 32) { // if it looks like a one-liner, crop at 128
      cropRect = new java.awt.Rectangle( 0, 0, 128, height );
     } else if ((width > 128) || (height > 128)) { // if only one dimension is > 128, scale smaller dimension down to 64, but ignore if smaller dimension is < 64
      scaleFactor = Math.min( 1.0, 64.0/Math.min( width, height ) );
     } else { // if both are < 128, let it slide...
      cropRect = new java.awt.Rectangle( 0, 0, width, height );
      }
     tileImage = GUIEffects.getImageScaledAndCropped( tileImage, scaleFactor, cropRect ); // src/edu/cmu/cs/stage3/alice/authoringtool/util/GUIEffects.java
     scaledAndCropped = true;
     }
    }

   if (valid) { // src/edu/cmu/cs/stage3/alice/authoringtool/util/GUIEffects.java
    tileImage = GUIEffects.getImageWithColoredBorder( tileImage, AuthoringToolResources.getColor( "dndHighlight2" ) );
   } else {
    tileImage = GUIEffects.getImageWithColoredBorder( tileImage, AuthoringToolResources.getColor( "dndHighlight3" ) );
    }

   if (dragWindow != null) {
    dragWindow.setImage( tileImage );
    }

   return scaledAndCropped;
   }
  }

 // public class DnDGrip extends javax.swing.JComponent
 public class DnDGrip extends javax.swing.JComponent {
  protected java.awt.Color highlightColor = javax.swing.plaf.metal.MetalLookAndFeel.getControlHighlight();
  protected java.awt.Color shadowColor = javax.swing.plaf.metal.MetalLookAndFeel.getControlDarkShadow();

  public DnDGrip () {
   setMinimumSize( new java.awt.Dimension( 6, 0 ) );
   setMaximumSize( new java.awt.Dimension( 6, Integer.MAX_VALUE ) );
   setPreferredSize( new java.awt.Dimension( 6, 0 ) );
   }

  //Rem @Override
  protected void printComponent (java.awt.Graphics g) {
   // do nothing
   }

  //Rem @Override
  protected void paintComponent (java.awt.Graphics g) {
   java.awt.Dimension size = getSize();

   g.setColor( highlightColor );
   for (int x = 0; x < size.width; x += 4) {
    for (int y = 0; y < size.height; y += 4) {
     g.drawLine( x, y, x, y );
     g.drawLine( x + 2, y + 2, x + 2, y + 2 );
     }
    }

   g.setColor( shadowColor );
   for (int x = 0; x < size.width; x += 4) {
    for (int y = 0; y < size.height; y += 4) {
     g.drawLine( x + 1, y + 1, x + 1, y + 1 );
     g.drawLine( x + 3, y + 3, x + 3, y + 3 );
     }
    }
   }

  } // public class DnDGrip extends javax.swing.JComponent

 } // public class DnDGroupingPanel extends GroupingPanel
